home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / ffuncs1.arc / BLDFUNCS.C next >
Encoding:
C/C++ Source or Header  |  1988-09-06  |  16.8 KB  |  529 lines

  1. /* BLDFUNC.C - Construct a table of the functions defined in src files.
  2.  * Copyright (c) 1988 Marvin Hymowech
  3.  *
  4.  * Usage:   bldfuncs file1.c file2.c ...
  5.  *          Wildcards are allowed also, e.g. *.c
  6.  *          The output table is named FUNCS.TXT
  7.  * 
  8.  * The typist changed all function names beginning with filter_...() to
  9.  * flt_...(). Example:  filter_data() changed to flt_data(). These were
  10.  * changed because the Mix Power C debugger only recognizes the first 8
  11.  * characters. Hence, it will report an internal CTRACE error (can't lo-
  12.  * cate symbol) with names like filter_ppdir() and filter_parens().
  13.  *    See the .DOC file in this .ARC file for information on setting up
  14.  * the environment variable GETFEDIT. Thes version of BLDFUNC will
  15.  * accept wildcards. To use GETF, the file constructed by BLDFUNC,
  16.  * FUNCS.TXT, must be in the same directory as GETF and both must be the
  17.  * default directory.
  18.  *    Also, see the .DOC file to see how BLDFUNC1 and GETF interact.
  19.  */
  20.  
  21. #include <stdio.h>
  22. #include <ctype.h>
  23. #include <string.h>
  24. #include <dos.h>
  25.  
  26. #define LINT_ARGS
  27.  
  28. #define TRUE  1
  29. #define FALSE 0
  30. #define OK    0
  31. #define ERROR 1
  32.  
  33. /* * return values for filter functions below.
  34.    * EOF or any character is also possible.
  35. */
  36.  
  37. #define MAXCHARS 64
  38. #define BRACES -2
  39. #define PARENS -3
  40. #define QUOTES -4
  41. #define MSDOSS     0x0021        /* Dos interrupt */
  42. #define SETDTA     0x1a00        /* Set Data Transfer Address func */
  43. #define SEARCHF    0x4e00        /* Search for first occurrence func */
  44. #define SEARCHN    0x4f00        /* Search for next occurrence func */
  45. #define ZEROATTRIB 0x0000        /* Search for normal files only */
  46. #define CARRYF     0x0001        /* position of carry flag */
  47.  
  48. /* DTA structure for reading directories */
  49.  
  50. struct DTA {
  51.    char reserved[21];         /* reserved by MS-DOS */
  52.    unsigned char attribute;   /* attr of file */
  53.    unsigned time;
  54.    unsigned date;
  55.    unsigned size_L;           /* file size - low word */
  56.    unsigned size_H;           /* file size - high word */
  57.    char fname[13];            /* parsed name of file */
  58. };
  59.  
  60. /* function declarations for type checking */
  61. char *get_fn_name(char *);
  62. int get_names_one_file(char *, FILE *);
  63.  
  64. main(argc, argv)
  65. int argc;
  66. char *argv[];
  67. {
  68.  
  69.    FILE *fp_out;
  70.    char *current_file;
  71.    char tempfile[MAXCHARS];
  72.    int num_files, i;
  73.    int cnt_bsl;
  74.    int carryf;
  75.    int bslpos;             /* position of last \ or : on command line */
  76.    struct DTA dtabuf;
  77.    union REGS inregs, outregs;
  78.  
  79.    if (argc < 2) {
  80.       fprintf( stderr, "\nWrong number of parameters");
  81.       exit(1);
  82.    }
  83.  
  84.    if ( (fp_out = fopen("FUNCS.TXT", "w")) == NULL ) {
  85.       fprintf( stderr, "Can't open %s\n", "FUNCS.TXT");
  86.       exit(1);
  87.    }
  88.  
  89.    /* Set Data Transfer Address so directory can be read. */
  90.    inregs.x.ax = SETDTA;         /* set data transfer area */
  91.    inregs.x.dx = (unsigned) &dtabuf;
  92.    int86 (MSDOSS, &inregs, &outregs);
  93.  
  94.    /* build a function list for each file on the command line
  95.    * and write the list to the file "FUNCS.TXT".
  96.    */
  97.  
  98.    /* tell the user where we're at */  /* this line (<---) is below in book*/
  99.    printf("Creating FUNCS.TXT...\n");
  100.    printf("\nFUNCS.TXT contains the following C files:\n\n");
  101.    num_files = argc - 1;
  102.    for (i = 1; i <= num_files; i++) {
  103.             /* use strlwr to lower-case name - cosmetic only */
  104.       strlwr (argv[i]);
  105.       if ( !ck_for_c(argv[i]) ) {
  106.          printf("File extension must be \".c\", %s not processed.\n", argv[i]);
  107.          printf("Hit a key to continue.\n");
  108.          getch();
  109.          continue;
  110.       }
  111.  
  112.       /* search for matching first file in directory */
  113.  
  114.       inregs.x.ax = SEARCHF;        /* search for first match func */
  115.       inregs.x.cx = ZEROATTRIB;     /* zero attrib for normal files */
  116.       inregs.x.dx = (unsigned) argv[i];   /* address of file */
  117.       int86(MSDOSS, &inregs, &outregs);
  118.       carryf = outregs.x.cflag;
  119.       if ((carryf & CARRYF) == CARRYF) {
  120.          printf("\n%s not found.", argv[i]);
  121.          continue;
  122.       }
  123.  
  124.       bslpos = getpath(argv[i]);    /* get position after last \ or : */
  125.  
  126.       /* search for matching next file in directory. First time */
  127.       /* through will process info from first match procedure above */
  128.  
  129.       while ((carryf & CARRYF) != CARRYF) {
  130.          for (cnt_bsl = 0; cnt_bsl < bslpos; cnt_bsl++)
  131.             tempfile[cnt_bsl] = argv[i][cnt_bsl];  /* put path in curr_file */
  132.          tempfile[cnt_bsl] = (char) NULL;
  133.  
  134.          strcat(tempfile, strlwr(dtabuf.fname)); /* add filename to path */
  135.          if ((carryf & CARRYF) == CARRYF) {
  136.             printf("\n\n%s not found.", tempfile);
  137.             exit(1);
  138.          }
  139.  
  140.          current_file = tempfile;
  141.          printf(" %30s:\n", current_file);
  142.          if (get_names_one_file (current_file, fp_out ) != OK ) {
  143.             fprintf( stderr, "\nCan't process %s", current_file);
  144.             exit(1);
  145.          }
  146.  
  147.          inregs.x.ax = SEARCHN;        /* search for next match func */
  148.          int86(MSDOSS, &inregs, &outregs);
  149.          carryf = outregs.x.cflag;
  150.       }     /* end while */
  151.    }     /* end for */
  152.  
  153.    fclose(fp_out);
  154.    exit(0);
  155. }
  156.  
  157.    /* open the c file source_file_name, scan it for function definitions,
  158.    *  and write a listing to fp_out in the form:
  159.    *        source_file_name:
  160.    *           function-1
  161.    *           function-2 ...
  162.    *           function-n;
  163.    *  Return values:  OK or ERROR
  164.    */
  165.  
  166. int get_names_one_file(source_file_name, fp_out)
  167. char *source_file_name;
  168. FILE *fp_out;
  169. {
  170.  
  171.    int line_len, c, got_fn_defn = FALSE;
  172.    #define LINE_LEN 8192
  173.    char line[LINE_LEN], *name_ptr, fn_name[64];
  174.    FILE *fp_source;
  175.  
  176.                               /* open the input source file */
  177.    if ( (fp_source = fopen(source_file_name, "r")) == NULL)
  178.       return ERROR;
  179.                               /* write "source file name:" */
  180.    sprintf( line, "\n%s:", source_file_name);
  181.    fprintf( fp_out, line);
  182.  
  183.    while( TRUE) {
  184.       line_len = 0;        /* using the flt_data() char stream */
  185.                            /* collect chars till a semicolon or PARENS */
  186.       while( (c = flt_data(fp_source)) != EOF && c != ';' && c != PARENS)
  187.          line[line_len++] = c;
  188.       if (c == EOF)
  189.          break;
  190.       if (c == ';')        /* Bypass externals representing data items */
  191.          continue;         /* Now we know line entered with PARENS */
  192.       line[line_len] = 0;  /* Truncate line */
  193.  
  194.             /* At this point, line either contains a function definition
  195.             *  or a function type declaration or something else, perhaps
  196.             *  an occurrence of parinthese in a data item definition.
  197.             *  We only want function definitions.
  198.             */
  199.                   /* Extract the function name from this possible */
  200.                   /* function definition, and save it in fn_name */
  201.       strcpy(fn_name, get_fn_name(line) );
  202.                   /* Exclude the case of parenthetical expressions in */
  203.                   /* a data definition, e.g. within srray brackets */
  204.       if ( !fn_name[0])
  205.          continue;
  206.                         /* skip white space */
  207.       while ( (c = flt_data(fp_source)) != EOF && isspace(c) )
  208.          ;
  209.       if (c == ';' || c == ',')     /* functs type check declaration */
  210.          continue;                  /* so bypass it */
  211.       if (c == EOF)
  212.          break;
  213.                         /* skip any parameter declarations - */
  214.       while (c != BRACES && c != EOF)  /* eat until braces or EOF */
  215.          c = flt_data(fp_source);
  216.  
  217.             /* append this function definition to the output table */
  218.       fprintf( fp_out, "\n\t%s", fn_name);
  219.       got_fn_defn = TRUE;
  220.    }     /* end while */
  221.    fclose(fp_source);
  222.                   /* got_fn_defn FALSE if no functions in file */
  223.                   /* write file terminator */
  224.    fputs( got_fn_defn ? ";\n" : "\n\t;\n", fp_out);
  225.    return OK;
  226. }  /* end get_names_one_file() */
  227.  
  228. /* assuming that the input line ends with a function name,
  229. *  extract and return this name (as a pointer into the input line)
  230. */
  231. char *get_fn_name(line)
  232. char *line;
  233. {
  234.  
  235.    char *name_ptr;
  236.    int len;
  237.  
  238.    if ( !(len = strlen(line)) )
  239.       return line;
  240.    name_ptr = line + len - 1;
  241.    while (isspace(*name_ptr))       /* skip trailing white space */
  242.       name_ptr--;
  243.    *(name_ptr + 1) = 0;             /* terminate fn name */
  244.  
  245.                               /* function names consist entirely of alpha- */
  246.                               /* numeric chars and underscores */
  247.    while ( (isalnum(*name_ptr) || *name_ptr == '_') && name_ptr >= line)
  248.       name_ptr--;
  249.                               /* if this alleged function name begins */
  250.    if ( isdigit(*++name_ptr)) /* with a digit, return an empty string */
  251.       return( name_ptr + strlen(name_ptr) );
  252.    return name_ptr;           /* else return the function name */
  253. }     /* end get_fn_name */
  254.  
  255. /* Using the stream returned by flt_parens() as input, 
  256. *  return a character stream in which any data initialization
  257. *  exptessions between an equals sign and a simicolon
  258. *  have been replaced by a single semicolon.
  259. *  This will filter out anything involving parentheses in a
  260. *  data initialization expression, which might otherwise be
  261. *  mistaken for a function definition.
  262. */
  263.  
  264. int flt_data(fp_source)
  265. FILE *fp_source;
  266. {
  267.  
  268.    int c;
  269.  
  270.    if ( (c = flt_parens(fp_source)) != '=')
  271.       return c;
  272.    while ( (c = flt_parens(fp_source)) != ';' && c != EOF)
  273.       ;
  274.    return c;
  275. }     /* end flt_data() */
  276.  
  277. /* Using the stream returned by flt_curly_braces() as input,
  278.  * reutrn a character stream in which all characters between
  279.  * '{' and the matching '}' have been replaced by the
  280.  * single special value PARENS (any nested parentheses within
  281.  * this top level pair will also have been eaten).
  282.  * This will filter out anything within the parentheses delimiting
  283.  * the arguments in a function definition.
  284.  */
  285.  
  286. int flt_parens(fp_source)
  287. FILE *fp_source;
  288. {
  289.  
  290.    int paren_cnt, c;
  291.  
  292.    if ( (c = flt_curly_braces(fp_source)) != '(' )
  293.       return c;
  294.    paren_cnt = 1;
  295.    while (paren_cnt)
  296.       switch (flt_curly_braces(fp_source)) {
  297.          case ')':
  298.             paren_cnt--;
  299.             break;
  300.          case '(':
  301.             paren_cnt++;
  302.             break;
  303.          case EOF:
  304.             return EOF;
  305.       }
  306.    return PARENS;
  307. }
  308.  
  309. /* Using the stream returned by flt_ppdir() as input,
  310.  * return a character stream in which all characters between
  311.  * '{' and the matching '}' have been replaced by the
  312.  * single special value BRACES (any nested braces within
  313.  * this top level pair will also have been eaten). This
  314.  * will filter out anything internal to a function.
  315.  */
  316.  
  317. int flt_curly_braces(fp_source)
  318. FILE *fp_source;
  319. {
  320.  
  321.    int brace_cnt,c;
  322.  
  323.    if( (c = flt_ppdir(fp_source) ) != '{')
  324.       return c;
  325.    brace_cnt = 1;
  326.    while (brace_cnt)       /* wait for brace count to return to zero */
  327.       switch (flt_ppdir(fp_source)) {
  328.          case '}':
  329.             brace_cnt--;
  330.             break;
  331.          case '{':
  332.             brace_cnt++;
  333.             break;
  334.          case EOF:
  335.             return EOF;
  336.       }
  337.    return BRACES;          /* brace count is now zero */
  338. }
  339.  
  340. #define MAXLINE 1024
  341.  
  342. /* Using the stream returned by flt_quotes() as input,
  343.  * return a character stream in which all preprocessor
  344.  * directives have been eaten.
  345.  */
  346.  
  347. int flt_ppdir(fp_source)
  348. FILE *fp_source;
  349. {
  350.  
  351.    int c, i;
  352.    char line [MAXLINE + 1];
  353.  
  354.    while (TRUE) {    /* Does this line begin a preprocessor directive? */
  355.       if ( (c = flt_quotes(fp_source)) != '#')
  356.          return c;      /* no, return character */
  357.                         /* yes, store until newline or EOF */
  358.       if ( (c = get_ppdir_line(fp_source, line)) == EOF)
  359.          return EOF;
  360.       if (strncmp(line, "define", 6))  /* if not #define directives */
  361.          continue;                     /* set this line */
  362.       if (line [strlen(line) - 1] != '\\')      /* If #define line */
  363.          continue;                              /* ends with "\"   */
  364.       else
  365.          while (TRUE) {    /* Keep eating lines which also end with "\" */
  366.                            /* Store until newline or EOF */
  367.             if ( (c = get_ppdir_line(fp_source, line)) == EOF)
  368.                return EOF;
  369.                      /* Done with this #define directive if this */
  370.                      /* line is not also a continuation line */
  371.             if ( line [strlen(line) - 1] != '\\')
  372.                break;
  373.          }  /* end while */
  374.    }  /* end while */
  375. }  /* end flt_ppdir() */
  376.  
  377. /* Utility routine used by flt_ppdir() -
  378. *  read the character stream using flt_quotes, storing characters
  379. *  in the parameter "line" until EOF or '\n' is encountered.
  380. *  Return EOF or '\n' accordingly.
  381. */
  382.  
  383. int get_ppdir_line(fp_source, line)
  384. FILE *fp_source;
  385. char *line;
  386. {
  387.  
  388.    int i, c;
  389.  
  390.    for (i = 0; i < MAXLINE && (c = flt_quotes(fp_source)) != '\n'
  391.                                     && c != EOF; i++)
  392.       line[i] = c;
  393.    line[i] = 0;            /* terminate string */
  394.    if (c == EOF)
  395.       return EOF;
  396.    return '\n';
  397. }
  398.  
  399. /* Using the stream returned by flt_cmt() as input,
  400.  * return a character stream in which any quoted character
  401.  * or quoted string has been collapsed to the single special value QUOTES
  402.  * to avoid considering special characters like '{', '}', '(', or ')'
  403.  * which may occur within quotes.
  404.  */
  405.  
  406. int flt_quotes(fp_source)
  407. FILE *fp_source;
  408. {
  409.  
  410.    int c1, c2;
  411.  
  412.    if ( (c1 = flt_cmt(fp_source)) != '\'' && c1 != '"')
  413.       return c1;  /* pass char through if not single or double quote */
  414.    while (TRUE)
  415.       switch (c2 = flt_cmt(fp_source)) {
  416.          case '\\':        /* beginning of an escape sequence */
  417.             flt_cmt(fp_source);  /* so eat next char */
  418.             break;
  419.          case EOF:
  420.             return EOF;
  421.          default:
  422.             if (c2 == c1)  /* found end of quoted char or string */
  423.                return QUOTES;
  424.       }  /* end switch */
  425. }  /* end flt_quotes() */
  426.  
  427. /* Returns character stream, eating comments.
  428.  * Returns EOF if end of file.
  429.  * Nested comments are allowed
  430.  */
  431.  
  432. int flt_cmt(fp_source)
  433. FILE *fp_source;
  434. {
  435.  
  436.    /* values for state */
  437.    #define STABLE 0        /* not in process of changing the comment */
  438.                            /* level: i.e., not in the middle of a */
  439.                            /* slash-star or star-slash combination */
  440.    #define IN_CMT_FS 1     /* got '/', looking for '*'  */
  441.    #define OUT_CMT_STAR 2  /* got '*', looking for '/'  */
  442.  
  443.    int c, state = STABLE, cmt_level = 0;
  444.  
  445.    while (TRUE) {
  446.       c = fgetc(fp_source);
  447.       if (c == EOF)
  448.          return EOF;
  449.       switch (state) {
  450.          case STABLE:
  451.             if (c == '*')
  452.                state = OUT_CMT_STAR;
  453.             else if (c == '/')
  454.                state = IN_CMT_FS;
  455.             break;
  456.  
  457.          case IN_CMT_FS:
  458.             if (c == '*') {
  459.                state = STABLE;
  460.                cmt_level++;         /* descend one comment level */
  461.                continue;
  462.             }
  463.             else if ( !cmt_level) {    /* If '/' not followed by '*'  */
  464.                ungetc (c, fp_source);  /* push back this char */
  465.                return '/';             /* and return the '/'    */
  466.             }
  467.             else if (c != '/')         /* stay in state IN_CMT_FS */
  468.                state = STABLE;      /* if next char is '/' as well */
  469.             break;
  470.  
  471.          case OUT_CMT_STAR:
  472.             if (c == '/') {
  473.                cmt_level--;         /* ascend one comment level */
  474.                state = STABLE;
  475.                continue;
  476.             }
  477.             else if ( !cmt_level) {    /* If '*' not followed by '/'  */
  478.                ungetc (c, fp_source);  /* push back this char */
  479.                return '*';             /* and return the '*'    */
  480.             }
  481.             else if (c != '*')         /* stay in state IN_CMT_FS */
  482.                state = STABLE;      /* if next char is '*' as well */
  483.             break;
  484.       }  /* end switch */
  485.       if (state == STABLE && !cmt_level)        /* if outside any comment */
  486.          return c;                              /* return character */
  487.    }  /* end while */
  488. }  /* end flt_cmt() */
  489.  
  490. /* ck_for_c() - makes sure the arguments to BLDFUNCS have
  491. *  .c extensions.
  492. */
  493. int ck_for_c(ch)
  494. char *ch;
  495. {
  496.  
  497.    int count = 0;
  498.  
  499.    while (ch [count++] != '.')
  500.       ;
  501.    if (ch [count] == 'c')
  502.       if (ch [++count] == 0)
  503.          return 1;
  504.    return 0;
  505. }
  506.  
  507. /* getpath() - get position of last backslash or
  508. *  colon on command line.
  509. */
  510. int getpath(path)
  511. char *path;
  512. {
  513.  
  514.    int count = 0;
  515.    int pos = 0;
  516.    char ch;
  517.  
  518.    while ((ch = *path) != (char) NULL) {
  519.       if (ch == '\\' || ch == ':')
  520.          pos = count;
  521.       count++;
  522.       path++;
  523.    }
  524.    if (pos == 0)
  525.       return 0;
  526.    return (pos + 1);
  527. }
  528.  
  529.